home *** CD-ROM | disk | FTP | other *** search
/ SGI Developer Toolbox 6.1 / SGI Developer Toolbox 6.1 - Disc 4.iso / src / swtools / libdmalloc / dmalloc.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-08-02  |  32.4 KB  |  1,340 lines

  1. /*
  2.  * Copyright (C) 1994, Silicon Graphics, Inc.
  3.  * All Rights Reserved.
  4.  *
  5.  * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics, Inc.;
  6.  * the contents of this file may not be disclosed to third parties, copied or
  7.  * duplicated in any form, in whole or in part, without the prior written
  8.  * permission of Silicon Graphics, Inc.
  9.  *
  10.  * RESTRICTED RIGHTS LEGEND:
  11.  * Use, duplication or disclosure by the Government is subject to restrictions
  12.  * as set forth in subdivision (c)(1)(ii) of the Rights in Technical Data
  13.  * and Computer Software clause at DFARS 252.227-7013, and/or in similar or
  14.  * successor clauses in the FAR, DOD or NASA FAR Supplement. Unpublished -
  15.  * rights reserved under the Copyright Laws of the United States.
  16.  */
  17. /*
  18.     Front-end to malloc that does counting and stuff.
  19.     Expects there to be a "real" malloc and free and realloc.
  20. */
  21.  
  22. #include "dmalloc.h"
  23. #include "stacktrace.h"
  24. #include <sys/types.h>
  25. #include <malloc.h>
  26. #include <stdio.h>
  27. #include <stdlib.h>
  28. #include <string.h>
  29. #include <bstring.h>
  30. #include <sys/param.h>
  31. #include <assert.h>
  32. #include <unistd.h>
  33. #include <stdarg.h>
  34. #include <fcntl.h>
  35. #include <ctype.h>
  36.  
  37. /*
  38.     sproc creates three spinlocks: __malloclock, __monlock, and __randlock.
  39.     We can't use __malloclock because we call the real malloc which uses it,
  40.     and that would cause deadlock.
  41. */
  42. static pid_t lock_owner;/* XXXassume shared--this may not be a good assumption*/
  43. static int lock_depth; /* number of times this process holds it */
  44. #define THELOCK __randlock
  45. extern ulock_t THELOCK;
  46. #ifdef LOCK_DEBUG
  47. #define lock_debug getenv("MALLOC_LOCK_DEBUG")
  48. #else
  49. #define lock_debug 0
  50. #endif
  51. static void
  52. LOCK_MALLOC(int inc)
  53. {
  54.     if (lock_debug)
  55.     printf("%d(%d): LOCKING %d+%d (owner=%d)\n", get_pid(), getpid(), lock_depth,inc,lock_owner);
  56.     if (!THELOCK) {
  57.     lock_depth += inc;
  58.     if (lock_debug)
  59.         printf("%d(%d): locked %d\n", get_pid(), getpid(), lock_depth);
  60.     return;                  /* no sprocs occured yet */
  61.     }
  62.  
  63.     if (lock_owner != get_pid()) {    /* someone else has it, or no one does */
  64.     ussetlock(THELOCK);
  65.     lock_owner = get_pid();
  66.     assert(lock_depth == 0);
  67.     } else {                  /* this process already has it */
  68.     assert(lock_depth > 0);
  69.     }
  70.  
  71.     lock_depth += inc;             /* we have the lock */
  72.     if (lock_debug)
  73.     printf("%d(%d): LOCKED %d\n", get_pid(), getpid(), lock_depth);
  74. }
  75. static void
  76. UNLOCK_MALLOC(int inc)
  77. {
  78.     if (lock_debug)
  79.     printf("%d(%d): UNLOCKING %d-%d (owner=%d)\n", get_pid(), getpid(), lock_depth,inc,lock_owner);
  80.     if (!THELOCK) {
  81.     lock_depth -= inc;
  82.     if (lock_debug)
  83.         printf("%d(%d): unlocked %d\n", get_pid(), getpid(), lock_depth);
  84.     return;                 /* no sprocs occured yet */
  85.     }
  86.  
  87.     assert(lock_owner == get_pid());
  88.     assert(lock_depth > 0);
  89.  
  90.     if ((lock_depth -= inc) == 0) {
  91.     lock_owner = 0;
  92.     usunsetlock(THELOCK);
  93.     }
  94.     if (lock_debug)
  95.     printf("%d(%d): UNLOCKED %d\n", get_pid(), getpid(), lock_depth);
  96. }
  97.  
  98. #define CREATE_MALLOC_LOCK() 0    /* not needed, since we use monlock */
  99.  
  100.  
  101. #undef MIN
  102. #define MIN(a,b) ((a)<(b)?(a):(b))
  103. #undef MAX
  104. #define MAX(a,b) ((a)>(b)?(a):(b))
  105. #define INRANGE(foo,bar,baz)    ((foo(bar))&&((bar)baz))
  106. #define streq(s,t) (strcmp(s, t) == 0)
  107.  
  108. #ifndef real_malloc
  109. #define real_malloc mAlLoC
  110. #endif
  111. #ifndef real_free
  112. #define real_free fReE
  113. #endif
  114. #ifndef real_realloc
  115. #define real_realloc rEaLlOc
  116. #endif
  117. #   ifdef __cplusplus
  118.     extern "C" {
  119. #   endif
  120. extern void *real_malloc(size_t);
  121. extern void real_free(void *);
  122. extern void *real_realloc(void *, size_t);
  123. #   ifdef __cplusplus
  124.     };
  125. #   endif
  126.  
  127. #define type_MALLOC ((void *)0)
  128. #define type_FREE ((void *)1)
  129.  
  130. #ifndef MAX_MALLOCS
  131. #define MAX_MALLOCS 10000    /* max number of occurrances of malloc&free */
  132. #endif
  133. #ifndef MAX_STACKTRACE_DEPTH
  134. #define MAX_STACKTRACE_DEPTH 10
  135. #endif
  136. #define MAX_SUM_OF_STACKTRACES (MAX_MALLOCS * MAX_STACKTRACE_DEPTH) /* XXX for now, until we do better bounds checking */
  137. #define SYMBUFSIZ 1024
  138.  
  139. struct hist {
  140.     void *type;                /* type_MALLOC or type_FREE */
  141.  
  142.     int ncalls, nbytes;
  143.     int ncalls_freed, nbytes_freed;    /* if it's a malloc */
  144.  
  145.     int stacktrace_depth;
  146.     void **stacktrace;            /* pointer into stacktraces buffer */
  147. };
  148.  
  149. /*
  150.  * Stuff that gets prepended and appended to each malloc block.
  151.  * Wow, that's a lot of stuff.
  152.  */
  153. static struct header {
  154.     int magic0, magic1;
  155.     int n;
  156.     struct hist *hist;
  157.     struct tailer *tail;
  158. #define LINKED_LIST
  159. #ifdef LINKED_LIST
  160.     struct header *prev, *next;        /* linked list */
  161. #endif /* LINKED_LIST */
  162.     int pad;    /* XXX fudge-- if this is removed, modify list below */
  163.     int magic2, magic3;
  164. } aheader = { 0xdeadbeef, 0xfedcba98, 0,0,0,
  165. #ifdef LINKED_LIST
  166.                          0,0, 
  167. #endif /* LINKED_LIST */
  168.                            0, 0x3456789a, 0xabbaabba};
  169. static struct tailer {
  170.     int magic4, magic5;
  171.     struct header *head;
  172.     int magic6, magic7;
  173. } atailer = { 0xcacacaca, 0x89898989, 0, 0xface6969, 0x81818181 };
  174.  
  175. #ifdef LINKED_LIST
  176. static struct header *firstheader = NULL;
  177. static void
  178. link_header(struct header *hdr)
  179. {
  180.     hdr->next = firstheader;
  181.     if (firstheader)
  182.     firstheader->prev = hdr;
  183.     hdr->prev = NULL;
  184.     firstheader = hdr;
  185. }
  186. static void
  187. unlink_header(struct header *hdr)
  188. {
  189.     if (hdr->next)
  190.     hdr->next->prev = hdr->prev;
  191.     if (hdr->prev)
  192.     hdr->prev->next = hdr->next;
  193.     else
  194.     firstheader = hdr->next;
  195. }
  196. #endif /* LINKED_LIST */
  197.  
  198. static struct header *lowest_head_ever = NULL, *highest_head_ever = NULL;
  199.  
  200. /* big static variables */
  201. static struct hist hists[MAX_MALLOCS];
  202. static int nhists = 0;
  203. static void *hists_stacktrace_buffer[MAX_SUM_OF_STACKTRACES];
  204. static int hists_stacktrace_buffer_size = 0;
  205.  
  206. static int ncalls_malloc = 0;
  207. static int ncalls_free = 0;
  208. static int nbytes_malloced = 0;
  209. static int nbytes_freed = 0;
  210.  
  211. static int ncalls_malloc_really = 0;    /* Not touched by reset */
  212. static int ncalls_free_really = 0;    /* Not touched by reset */
  213. static int nbytes_malloced_really = 0;    /* Not touched by reset */
  214. static int nbytes_freed_really   = 0;    /* Not touched by reset */
  215. static int max_diff_bytes    = 0;    /* Not touched by reset */
  216.  
  217. static void *malloc_block_of_interest = NULL;
  218. static int malloc_call_of_interest = -1;
  219. static int depth_of_trace_of_interest = -1;
  220. static void *trace_of_interest[MAX_STACKTRACE_DEPTH];
  221.  
  222. #define MALLOC_FILL '\001'
  223. #define FREE_FILL   '\002'
  224.  
  225. static void
  226. fdprintf(int fd, char *fmt, ...)
  227. {
  228.     char buf[MAXPATHLEN*2];
  229.     va_list args;
  230.  
  231.     va_start(args, fmt);
  232.  
  233.     vsprintf(buf, fmt, args);
  234.     write(fd, buf, strlen(buf));
  235.  
  236.     va_end(args);
  237. }
  238.  
  239.  
  240. /* external parameters user can mess with -- maybe should be mallopt option */
  241. int malloc_stacktrace_get_depth = 0;    /* default is don't trace */
  242. int malloc_fillarea = 1;        /* fill area by default */
  243. extern void malloc_init_function();
  244.  
  245. static void
  246. _atexit()
  247. {
  248.     int do_info = 0, do_free = 0, do_check = 1;         /* note default values */
  249.     char *p;
  250.  
  251.     if (p = getenv("MALLOC_INFO_ATEXIT"))
  252.     do_info = (*p ? atoi(p) : 1);
  253.     if (p = getenv("FREE_ATEXIT"))
  254.     do_free = (*p ? atoi(p) : 1);
  255.     if (p = getenv("MALLOC_CHECK_ATEXIT"))
  256.     do_check = (*p ? atoi(p) : 1);
  257.  
  258.     if (do_info)
  259.     malloc_info(0, -1);
  260.  
  261. #ifdef LINKED_LIST
  262.     if (do_free) {
  263.     if (do_free >= 2) {
  264.         fdprintf(2, "%s(%d): Freeing everything...",
  265.             stacktrace_get_argv0() ? stacktrace_get_argv0() : "",
  266.             getpid());
  267.     }
  268.  
  269.     LOCK_MALLOC(1);
  270.     while (firstheader)
  271.         free((void *)(firstheader+1));
  272.     UNLOCK_MALLOC(1);
  273.  
  274.     if (do_free >= 2)
  275.         fdprintf(2, "done.\n");
  276.     }
  277.  
  278.     if (do_check) {
  279.     if (do_check >= 2) {
  280.         fdprintf(2, "%s(%d): Checking malloc chain at exit...",
  281.             stacktrace_get_argv0() ? stacktrace_get_argv0() : "",
  282.             getpid());
  283.     }
  284.  
  285.     malloc_check_during("exit");
  286.  
  287.     if (do_check >= 2)
  288.         fdprintf(2, "done.\n");
  289.     }
  290. #endif /* LINKED_LIST */
  291. }
  292.  
  293. #ifdef LINKED_LIST
  294. extern int
  295. malloc_check_during(char *during)
  296. {
  297.     int is_bad = 0;
  298.     struct header *p;
  299.  
  300.     LOCK_MALLOC(1);
  301.     for (p = firstheader; p; p = p->next)
  302.     if (!malloc_isgoodblock_during(p+1, during))
  303.         is_bad = 1;
  304.     UNLOCK_MALLOC(1);
  305.  
  306.     return is_bad ? -1 : 0;
  307. }
  308. extern int
  309. malloc_check()
  310. {
  311.     return malloc_check_during("malloc_check");
  312. }
  313. #endif /* LINKED_LIST */
  314.  
  315. static void
  316. init_from_env()
  317. {
  318.     static int called_already = 0;
  319.     if (!called_already) {
  320.     char *p;
  321.  
  322.     /* try to snarf argv[0] as soon as possible, in case main clobbers it */
  323.     (void)stacktrace_get_argv0();
  324.  
  325.     if (p = getenv("MALLOC_FILLAREA"))
  326.         malloc_fillarea = (*p ? atoi(p) : 1);
  327.     if (p = getenv("MALLOC_STACKTRACE_GET_DEPTH"))
  328.         malloc_stacktrace_get_depth = (*p ? atoi(p) : 0);
  329.  
  330.     /* XXX it might be useful to make a nice callback interface... */
  331.     /* XXX and definitely want a gui */
  332.     if (p = getenv("MALLOC_STACKTRACE_OF_INTEREST")) {
  333.         depth_of_trace_of_interest =
  334.         sscanf(p, "%x %x %x %x %x %x %x %x %x %x",
  335.             &trace_of_interest[0],
  336.             &trace_of_interest[1],
  337.             &trace_of_interest[2],
  338.             &trace_of_interest[3],
  339.             &trace_of_interest[4],
  340.             &trace_of_interest[5],
  341.             &trace_of_interest[6],
  342.             &trace_of_interest[7],
  343.             &trace_of_interest[8],
  344.             &trace_of_interest[9]);
  345.         if (depth_of_trace_of_interest == -1)
  346.         depth_of_trace_of_interest = 0;    /* dumbass sscanf */
  347.     }
  348.     /*
  349.      * Note: we must have some code in this file that
  350.      * sets the value of malloc_call_of_interest,
  351.      * otherwise we will not be able to set it properly in the debugger
  352.      * (due to compiler optimization or something).
  353.      */
  354.     /* XXX want a gui for this */
  355.     if (p = getenv("MALLOC_CALL_OF_INTEREST"))
  356.         malloc_call_of_interest = (int) strtoul(p, (char **)NULL, 0);
  357.     if (p = getenv("MALLOC_BLOCK_OF_INTEREST"))
  358.         malloc_block_of_interest = (void *)strtoul(p, (char **)NULL, 0);
  359.  
  360.     if (p = getenv("MALLOC_PROMPT_ON_STARTUP")) {
  361.         if (!*p || streq(p, stacktrace_get_argv0())) {
  362.         int tty = open("/dev/tty", 2);
  363.         char c;
  364.         assert(tty >= 0);
  365.         fdprintf(tty, "%s(%d): hit return to continue",
  366.                   stacktrace_get_argv0(), getpid());
  367.         read(tty, &c, 1);
  368.         close(tty);
  369.         }
  370.     }
  371.     
  372.  
  373.     malloc_init_function();        /* call application-defined function */
  374.  
  375.     atexit(_atexit);
  376.  
  377.     called_already = 1;
  378.     /*
  379.     called_already must be true at this point,
  380.     so that this block won't get re-entered
  381.     if the us_ routines call malloc.
  382.     */
  383.     CREATE_MALLOC_LOCK();
  384.  
  385.     }
  386. }
  387.  
  388.  
  389. #define MALLOC_STACKTRACE_GET_DEPTH (malloc_stacktrace_get_depth == -1 ? MAX_STACKTRACE_DEPTH : MIN(malloc_stacktrace_get_depth, MAX_STACKTRACE_DEPTH))
  390.  
  391. /* only compares up to the min of the two sizes */
  392. static int
  393. stacktracecmp(int siz0, void *trace0[], int siz1, void *trace1[])
  394. {
  395.     int i;
  396.     for (i = 0; i < siz0 && i < siz1; ++i)
  397.         if (((unsigned long *)trace0)[i] != ((unsigned long *)trace1)[i]) {
  398.         if (((unsigned long *)trace0)[i] < ((unsigned long *)trace1)[i])
  399.             return -1;
  400.         else
  401.             return 1;
  402.         }
  403.     return siz0 - siz1;
  404. }
  405.  
  406. static int
  407. stacktracencmp(int siz0, void *trace0[], int siz1, void *trace1[], int n)
  408. {
  409.     int i;
  410.     for (i = 0; i < siz0 && i < siz1 && i < n; ++i)
  411.         if (((unsigned long *)trace0)[i] != ((unsigned long *)trace1)[i]) {
  412.         if (((unsigned long *)trace0)[i] < ((unsigned long *)trace1)[i])
  413.             return -1;
  414.         else
  415.             return 1;
  416.         }
  417.     if (i == n)
  418.         return 0;
  419.     return siz0 - siz1;
  420. }
  421.  
  422. /* simple prime testing-- we only need it to initialize hashsiz */
  423. static int 
  424. isprime(int n)
  425. {
  426.     int i;
  427.     if (n % 2 == 0)
  428.     return 0;
  429.     for (i = 3; i*i <= n; ++i)
  430.     if (n % i == 0)
  431.         return 0;
  432.     return 1;
  433. }
  434.  
  435. static int
  436. hashfun(int depth, void *trace[], int hashsiz)
  437. {
  438.     int i; /* not unsigned! or (i < depth) will be true when i==0 and depth<0 */
  439.     unsigned long sum = 0;
  440.     for (i = 0; i < depth; ++i)
  441.     sum += (((unsigned long)trace[i])/4);
  442.     return sum % (hashsiz-1) + 1;    /* in range 1..hashsiz-1 */
  443. }
  444.  
  445. #ifdef HASH_STATS
  446.     static int n_collisions = 0;
  447.     static int n_distinct_collisions = 0;
  448.     static int n_pileups;
  449.     static int n_distinct_pileups;
  450.     static int max_pileup = 0;
  451.     extern void
  452.     _malloc_history_print_stats()
  453.     {
  454.     printf("%d max pileup\n", max_pileup);
  455.     printf("%d distinct pileups\n", n_distinct_pileups);
  456.     printf("%d total pileups\n", n_pileups);
  457.     printf("%d distinct collisions\n", n_distinct_collisions);
  458.     printf("%d total collisions\n", n_collisions);
  459.     }
  460. #endif
  461.  
  462. static struct hist *
  463. find_existing_hist(void *type, int stacktrace_depth, void *stacktrace[])
  464. {
  465. #ifndef HASHSIZ
  466. #define HASHSIZ (MAX_MALLOCS * 3/2)
  467. #endif
  468.     static struct hist *hashtable[HASHSIZ];
  469.     static int hashsiz = 0;
  470.     int i, hash;
  471. #ifdef HASH_STATS
  472.     int pileup = 0;
  473. #endif
  474.  
  475.     /*
  476.      * Make the size of the hash table prime so that
  477.      * for every hash, 0 < hash < hashsiz, the sequence
  478.      *        hash, 2*hash, 3*hash, ... (mod hashsiz)
  479.      * is a unique path through 1..hashsize-1 (this allows a simple
  480.      * rehashing mechanism that avoids pileups).
  481.      * Note that 0 is not allowed-- make sure hashfun() can not return 0!
  482.      * (hashtable[0] is not used, but subtracting 1 from everything is
  483.      * not worth the trouble).
  484.      */
  485.     if (!hashsiz)    /* then hashsiz hasn't been initialized yet */
  486.     for (hashsiz = HASHSIZ; !isprime(hashsiz); hashsiz--)
  487.         ;
  488.  
  489.     hash = hashfun(stacktrace_depth, stacktrace, hashsiz);
  490.     for (i = hash; hashtable[i];
  491. #ifdef HASH_STUPID
  492.                  i++
  493. #else
  494.                  i = (i+hash) % hashsiz
  495. #endif
  496.                                ) {
  497.     if (!stacktracecmp(stacktrace_depth, stacktrace,
  498.                hashtable[i]->stacktrace_depth,
  499.                hashtable[i]->stacktrace)) {
  500.         return hashtable[i];
  501.     }
  502. #ifdef HASH_STATS
  503.     pileup++;
  504.     n_collisions++;
  505.     n_pileups += (pileup == 1);
  506. #endif
  507.     }
  508.     if (nhists == MAX_MALLOCS)
  509.     return NULL;
  510.  
  511. #ifdef HASH_STATS
  512.     n_distinct_collisions += pileup;
  513.     n_distinct_pileups += (pileup > 0);
  514.     max_pileup = MAX(pileup, max_pileup);
  515. #endif
  516.  
  517.     hashtable[i] = &hists[nhists];
  518.     return hashtable[i];
  519. }
  520.  
  521. /* just places for the debugger to stop... */
  522. extern void
  523. malloc_of_interest()
  524. {
  525.     printf("");        /* make sure this function doesn't get optimized out */
  526. }
  527.  
  528. static struct hist *
  529. findhist(void *type, int stacktrace_depth, void *stacktrace[])
  530. {
  531.     int i;
  532.     struct hist *h;
  533.  
  534.     h = find_existing_hist(type, stacktrace_depth, stacktrace);
  535.  
  536.     if (h == NULL) {
  537.     static int already_complained = 0;
  538.     if (!already_complained) {
  539.         fdprintf(2, "Turning off malloc tracing: more than %d distinct mallocs & frees\n", MAX_MALLOCS);
  540.         already_complained = 1;
  541.     }
  542.     return NULL;
  543.     }
  544.  
  545.     if (depth_of_trace_of_interest >= 0
  546.      && !stacktracecmp(stacktrace_depth, stacktrace,
  547.         depth_of_trace_of_interest, trace_of_interest)) {
  548.     malloc_of_interest();
  549.     /* make each one separate XXXthis should go with other bounds checking*/
  550.     if (nhists < MAX_MALLOCS) {
  551.         h = hists+nhists;
  552.     }
  553.     }
  554.  
  555.     if (h-hists == nhists) {    /* then it wasn't really existing */
  556.     nhists++;
  557.  
  558.     h->type   = type;
  559.     h->ncalls  = 0;
  560.     h->nbytes  = 0;
  561.     h->ncalls_freed = 0;
  562.     h->nbytes_freed = 0;
  563.  
  564.     /* XXX need to do some bounds checking here */
  565.     h->stacktrace_depth = MIN(stacktrace_depth, MAX_STACKTRACE_DEPTH);
  566.     h->stacktrace = hists_stacktrace_buffer + hists_stacktrace_buffer_size;
  567.     hists_stacktrace_buffer_size += h->stacktrace_depth;
  568.     for (i = 0; i < h->stacktrace_depth; ++i)
  569.         h->stacktrace[i] = stacktrace[i];
  570.     }
  571.  
  572.     return h;
  573. }
  574.  
  575. /*
  576.  * Stuff to do on each malloc or realloc
  577.  */
  578. static void
  579. malloc_do_stuff(size_t n, struct header *head)
  580. {
  581.     struct hist *h;
  582.     int stacktrace_depth;
  583.     void *stacktrace[MAX_STACKTRACE_DEPTH];
  584.  
  585.     if (malloc_block_of_interest == (void *)(head+1))
  586.     malloc_of_interest();
  587.     if (malloc_call_of_interest == ncalls_malloc)
  588.     malloc_of_interest();
  589.  
  590.     if (!lowest_head_ever || head < lowest_head_ever)
  591.     lowest_head_ever = head;
  592.     if (!highest_head_ever || head > highest_head_ever)
  593.     highest_head_ever = head;
  594.  
  595.     ncalls_malloc++;
  596.     ncalls_malloc_really++;
  597.     nbytes_malloced += n;
  598.     nbytes_malloced_really += n;
  599.  
  600.     if (nbytes_malloced_really - nbytes_freed_really > max_diff_bytes)
  601.     max_diff_bytes = nbytes_malloced_really - nbytes_freed_really;
  602.  
  603.     /* don't get any traces in recursive mallocs */
  604.     if (lock_depth >= 200)
  605.     stacktrace_depth = 0;
  606.     else
  607.     stacktrace_depth = stacktrace_get(2, MALLOC_STACKTRACE_GET_DEPTH,
  608.                          stacktrace);
  609.  
  610.     h = findhist(type_MALLOC, stacktrace_depth, stacktrace);
  611.     if (h) {
  612.     h->ncalls++;
  613.     h->nbytes += n;
  614.     }
  615.  
  616.     head->n = n;
  617.     head->hist = h;
  618.  
  619. #ifdef LINKED_LIST
  620.     link_header(head);
  621. #endif
  622. }
  623.  
  624. static int
  625. strcontains(char *S, char *s)    /* XXX remove this when no longer used */
  626. {
  627.     if (!S || !s)
  628.     return 0;
  629.     for (; *S; S++)
  630.     if (!strncmp(S, s, strlen(s)))
  631.         return 1;
  632.     return 0;
  633. }
  634.  
  635. /*
  636.     Are we suppressing messages about this block
  637.     because of an environment variable?
  638. */
  639. static int
  640. suppressing(void *block)
  641. {
  642.     char *p = getenv("MALLOC_SUPPRESS");
  643.     if (!p)
  644.     return 0;
  645.  
  646.     while (p && *p) {
  647.     char argv0_to_suppress[4096];
  648.     long block_to_suppress = 0;
  649.     while (*p && isspace(*p))
  650.         p++;
  651.     if (sscanf(p, "%[^:]:%lx", argv0_to_suppress, &block_to_suppress) != 2){
  652.         argv0_to_suppress[0] = '\0';
  653.         if (sscanf(p, "%lx", &block_to_suppress) != 1)
  654.         break;
  655.     }
  656.  
  657.     if (streq(argv0_to_suppress, stacktrace_get_argv0())
  658.      && block_to_suppress == (long)block)
  659.         return 1;    /* found it; suppress it */
  660.     while (*p && !isspace(*p))
  661.         p++;
  662.     while (*p && isspace(*p))
  663.         p++;
  664.     }
  665.     return 0;    /* not found in suppress list; don't suppress */
  666. }
  667.  
  668. extern void    /* can stop here for breakpoint debugging */
  669. malloc_bad(void *block)
  670. {
  671.     printf("");    /* make sure it doesn't get optimized out */
  672. }
  673.  
  674. extern int
  675. malloc_isgoodblock_during(void *block, char *during)/* XXX think of a better name */
  676. {
  677.     int its_bad = 0;
  678.     struct header *head = ((struct header *)block) - 1;
  679.     struct tailer *tail;
  680.     int nwrong_in_head, nwrong_in_tail;
  681.     char *p;
  682.  
  683.     /*
  684.      * Sanity check so we don't buserror ourself
  685.      */
  686.     if (((long)head & 3L) ||
  687.     head < lowest_head_ever || head > highest_head_ever) {
  688.     fdprintf(2, "%s(%d): WARNING: %#x is not a valid malloced block,\n\tdetected during %s\n",
  689.             stacktrace_get_argv0() ? stacktrace_get_argv0() : "",
  690.             getpid(),
  691.             head+1, during);
  692.     malloc_bad(block);
  693.     return 0; /* failure */
  694.     }
  695.  
  696.     /*
  697.      * Heavy duty bounds checking
  698.      */
  699.     nwrong_in_head = (head->magic0 != aheader.magic0)
  700.            + (head->magic1 != aheader.magic1)
  701.            + (head->magic2 != aheader.magic2)
  702.            + (head->magic3 != aheader.magic3);
  703.     if (nwrong_in_head > 0) {
  704.     if (!suppressing(head+1))
  705.         fdprintf(2,
  706.         "%s(%d): ERROR: underflow corruption detected during %s\n\tat malloc block %#x\n",
  707.             stacktrace_get_argv0() ? stacktrace_get_argv0() : "",
  708.             getpid(),
  709.             during,
  710.             head+1);
  711.     its_bad = 1;
  712.     }
  713.     tail = head->tail;
  714.     nwrong_in_tail = (tail->magic4 != atailer.magic4)
  715.            + (tail->magic5 != atailer.magic5)
  716.            + (tail->head != head)
  717.            + (tail->magic6 != atailer.magic6)
  718.            + (tail->magic7 != atailer.magic7);
  719.     /* check that the < 4 bytes of extra alignment space are
  720.        still filled with MALLOC_FILL */
  721.     for (p = (char *)(head+1) + head->n; p < (char *)tail; ++p)
  722.     if (*p != MALLOC_FILL)
  723.         nwrong_in_tail++;
  724.  
  725.     if (nwrong_in_tail > 0) {
  726.     if (!suppressing(head+1))
  727.         fdprintf(2, "%s(%d): ERROR: overflow corruption detected during %s\n\tat malloc block %#x (%s%d bytes)\n",
  728.             stacktrace_get_argv0() ? stacktrace_get_argv0() : "",
  729.             getpid(),
  730.             during,
  731.             head+1,
  732.             nwrong_in_head ? "maybe " : "",
  733.             head->n);
  734.     its_bad = 1;
  735.     }
  736.     if (!nwrong_in_head && !nwrong_in_tail && ((long)head->hist & 1)) {
  737.     /*
  738.      * When we free the block, we set the loworder bit of hist.
  739.      * Of course the real free and malloc may clobber it,
  740.      * but if that happened, the above never would have passed.
  741.      */
  742.     if (!suppressing(head+1))
  743.         fdprintf(2, "WARNING: %#x (%d bytes) has been freed already,\n\tdetected during %s\n",
  744.             head+1, head->n, during);
  745.     its_bad = 1;
  746.     }
  747.  
  748.     if (its_bad) {
  749.     char buf[100];
  750.     /* snarf the stacktrace away; since the block has been freed
  751.        already, our printing may clobber it */
  752.     int stacktrace_depth;
  753.     void *stacktrace[MAX_STACKTRACE_DEPTH];
  754.     stacktrace_depth = ((struct hist *)((long)head->hist&~1))->stacktrace_depth;
  755.     bcopy(((struct hist *)((long)head->hist&~1))->stacktrace, stacktrace,
  756.         stacktrace_depth * sizeof(*stacktrace));
  757.  
  758.     malloc_bad(block);
  759.  
  760.     /*
  761.         XXX Quick semi-accurate attempt to see whether we are in a DSO--,
  762.         since we will probably core dump if we are and the main
  763.         program is stripped and we try to get a stack trace.
  764.     */
  765.     if (!suppressing(head+1) &&
  766.        (strcontains(getenv("_RLD_LIST"), "libdmalloc")
  767.              && getenv("_MALLOC_TRY_TO_PRINT_STACKTRACES")
  768.         ||!strcontains(getenv("_RLD_LIST"), "libdmalloc")
  769.              && !getenv("_MALLOC_DONT_TRY_TO_PRINT_STACKTRACES"))) {
  770.  
  771.         simple_stacktrace_print(/*fd*/2, NULL, /*skip*/3, 100);
  772.     }
  773.  
  774.     if (!suppressing(head+1) &&
  775.        (strcontains(getenv("_RLD_LIST"), "libdmalloc")
  776.              && getenv("_MALLOC_TRY_TO_PRINT_STACKTRACES")
  777.         ||!strcontains(getenv("_RLD_LIST"), "libdmalloc")
  778.              && !getenv("_MALLOC_DONT_TRY_TO_PRINT_STACKTRACES"))) {
  779.         fdprintf(2, "This block may have been allocated here:\n");
  780.         simple_stacktrace_write(/*fd*/2, /*fmt*/NULL, /*filename*/NULL,
  781.             stacktrace_depth, stacktrace);
  782.     }
  783.  
  784.     return 0;    /* failure */
  785.     }
  786.  
  787.     return 1;    /* success */
  788. }
  789. extern int
  790. malloc_isgoodblock(void *block) /* XXX think of a better name */
  791. {
  792.     return malloc_isgoodblock_during(block, "malloc_isgoodblock");
  793. }
  794.  
  795.  
  796. /*
  797.  * Stuff to do on each free or realloc.
  798.  * Return 1 on success, 0 if corruption was detected.
  799.  */
  800. static int
  801. free_do_stuff(struct header *head, char *during)
  802. {
  803.     struct hist *h;
  804.     int stacktrace_depth;
  805.     void *stacktrace[MAX_STACKTRACE_DEPTH];
  806.  
  807.     if (!malloc_isgoodblock_during(head+1, during))
  808.     return 0;    /* failure */
  809.  
  810.     ncalls_free++;
  811.     ncalls_free_really++;
  812.     nbytes_freed       += head->n;
  813.     nbytes_freed_really += head->n;
  814.  
  815.     if (lock_depth >= 200)
  816.     stacktrace_depth = 0;
  817.     else
  818.     stacktrace_depth = stacktrace_get(2, MALLOC_STACKTRACE_GET_DEPTH,
  819.                          stacktrace);
  820.  
  821.     h = findhist(type_FREE, stacktrace_depth, stacktrace);
  822.     if (h) {
  823.     h->ncalls++;
  824.     h->nbytes += head->n;
  825.     }
  826.  
  827.     if (head->hist) {
  828.     head->hist->ncalls_freed++;
  829.     head->hist->nbytes_freed += head->n;
  830.     }
  831.  
  832. #ifdef LINKED_LIST
  833.     unlink_header(head);
  834. #endif
  835.  
  836.     return 1;    /* success */
  837. }
  838.  
  839. #define ALIGNUP(n) (((n)+3)&~3)
  840.  
  841. extern void
  842. malloc_failed()
  843. {
  844.     /* this function exists for breakpoint debugging. */
  845.     printf("");        /* make sure this function doesn't get optimized out */
  846.     /* XXX maybe should allow a callback here? */
  847. }
  848.  
  849. /*
  850.  * Front end to the real malloc
  851.  */
  852. extern void *
  853. malloc(size_t n)
  854. {
  855.     struct header *head;
  856.  
  857.     init_from_env();
  858.  
  859.     LOCK_MALLOC(100);
  860.  
  861.     head = 0;    /* XXX suppress stupid compiler warning */
  862.     head = (struct header *) real_malloc(ALIGNUP(n + sizeof(*head))
  863.                     + sizeof(struct tailer));
  864.     if (!head) {
  865.     malloc_failed();
  866.     UNLOCK_MALLOC(100);
  867.     return NULL;
  868.     }
  869.  
  870.     *head = aheader;
  871.     head->tail = (struct tailer *)(((char *)head) + ALIGNUP(n + sizeof(*head)));
  872.     *head->tail = atailer;
  873.     head->tail->head = head;
  874.  
  875.     malloc_do_stuff(n, head);
  876.  
  877.     if (malloc_fillarea)
  878.     memset((void *)(head+1), MALLOC_FILL, n);
  879.  
  880.     /* always fill any space after the buffer and before the tail,
  881.        for overflow detection */
  882.     memset((void *)((char *)(head+1)+n),
  883.        MALLOC_FILL,
  884.        (char *)head->tail - ((char *)(head+1)+n));
  885.  
  886.     UNLOCK_MALLOC(100);
  887.     return (void *)(head+1);
  888. }
  889.  
  890. /*
  891.  * Front end to the real free
  892.  */
  893. extern void
  894. free(void *p)
  895. {
  896.     struct header *vom;
  897.  
  898.     init_from_env();
  899.  
  900.     LOCK_MALLOC(100);
  901.  
  902.     if (!p) {
  903.     UNLOCK_MALLOC(100);
  904.     return;        /* XXX do we want to save this information? */
  905.     }
  906.     vom = ((struct header *)p) - 1;
  907.  
  908.     if (!free_do_stuff(vom, "free")) {
  909.     UNLOCK_MALLOC(100);
  910.     return;            /* free_do_stuff prints its own error message */
  911.     }
  912.  
  913.     if (malloc_fillarea)
  914.     memset((void *)(vom+1), FREE_FILL, vom->n);
  915.  
  916.     vom->hist = (struct hist *)((long)vom->hist | 1);
  917.  
  918.     real_free((void *)vom);
  919.  
  920.     UNLOCK_MALLOC(100);
  921. }
  922.  
  923. /*
  924.  * Front end to the real realloc
  925.  */
  926. extern void *
  927. realloc(void *p, size_t n)
  928. {
  929.     struct header *head;
  930.     int old_n;
  931.  
  932.     if (!p)
  933.     return malloc(n);    /* this is what the sgi man page says, anyway */
  934.  
  935.     init_from_env();
  936.  
  937.     LOCK_MALLOC(100);
  938.  
  939.     head = ((struct header *)p) - 1;
  940.  
  941.     old_n = head->n;
  942.  
  943.     if (!free_do_stuff(head, "realloc")) {
  944.     UNLOCK_MALLOC(100);
  945.     return NULL;        /* free_do_stuff prints its own error message */
  946.     }
  947.  
  948.     if (malloc_fillarea && n < old_n)
  949.     memset((void *)((char *)(head+1) + n), FREE_FILL, old_n - n);
  950.  
  951.     head = (struct header *) real_realloc((void *)head,
  952.                 ALIGNUP(n + sizeof(*head)) + sizeof(struct tailer));
  953.  
  954.     if (!head) {
  955.     UNLOCK_MALLOC(100);
  956.     return NULL;        /* XXX do we want to save this information? */
  957.     }
  958.  
  959.     head->tail = (struct tailer *)(((char *)head) + ALIGNUP(n+sizeof(*head)));
  960.     *head->tail = atailer;
  961.     head->tail->head = head;
  962.  
  963.     malloc_do_stuff(n, head);
  964.  
  965.     if (malloc_fillarea && n > old_n)
  966.     memset((void *)((char *)(head+1) + old_n), MALLOC_FILL, n - old_n);
  967.  
  968.     /* always fill any space after the buffer and before the tail,
  969.        for overflow detection */
  970.     memset((void *)((char *)(head+1)+n),
  971.        MALLOC_FILL,
  972.        (char *)head->tail - ((char *)(head+1)+n));
  973.  
  974.     UNLOCK_MALLOC(100);
  975.     return (void *)(head + 1);
  976. }
  977.  
  978.  
  979. /*
  980.  * Sorting utilities
  981.  */
  982. static void
  983. multiqsort(char *base, int n, int elsiz, int (*cmps[])(const void *, const void *))
  984. /* cmps is a null-terminated array of comparison functions */
  985. {
  986.     int i, (*cmp)(const void *, const void *);
  987.  
  988.     if (!(cmp = cmps[0]))
  989.     return;
  990.  
  991.     qsort(base, n, elsiz, cmp);
  992.  
  993.     if (cmps[1])
  994.     for (; n > 0; n -= i, base += i*elsiz) {
  995.         for (i = 0; i < n; ++i)
  996.         if ((*cmp)(base, base + i*elsiz))
  997.             break;
  998.         if (i > 1)
  999.         multiqsort(base, i, elsiz, cmps+1);
  1000.     }
  1001. }
  1002.  
  1003. static int cmp_leaks(struct hist **a, struct hist **b)
  1004. {
  1005.     return ((*b)->nbytes - (*b)->nbytes_freed)
  1006.      - ((*a)->nbytes - (*a)->nbytes_freed);        /* highest first */
  1007. }
  1008.  
  1009. static int cmp_ncalls(struct hist **a, struct hist **b)
  1010. {
  1011.     return (*b)->ncalls - (*a)->ncalls;            /* highest first */
  1012. }
  1013.  
  1014. static int cmp_stacktrace(struct hist **a, struct hist **b)
  1015. {
  1016.     return stacktracecmp((*a)->stacktrace_depth, (*a)->stacktrace, (*b)->stacktrace_depth, (*b)->stacktrace);
  1017. }
  1018.  
  1019. #if 0    /* maybe someday we'll do this by filename */
  1020. static int cmp_lineno(struct hist *a, struct hist *b)
  1021. {
  1022.     return (*a)->lineno - (*b)->lineno;
  1023. }
  1024.  
  1025. static int cmp_filename(struct hist **a, struct hist **b)
  1026. {
  1027.     if (!(*a)->file || !(*b)->file)
  1028.     return !(*a)->file - !(*b)->file;    /* with filename comes before without filename */
  1029.     return strcmp((*a)->file, (*b)->file);
  1030. }
  1031.  
  1032. static int cmp_diffbytes(struct hist **a, struct hist **b)
  1033. {
  1034.     return ((*a)->bytes - (*a)->fbytes) - ((*b)->bytes - (*b)->fbytes);
  1035. }
  1036. #endif /* 0 */
  1037.  
  1038. static int cmp_malloc_then_free(struct hist **a, struct hist **b)
  1039. {
  1040.     return ((*a)->type == type_FREE) - ((*b)->type == type_FREE);
  1041. }
  1042.  
  1043. int (*oldcmps[])(const void *, const void *) = {
  1044.     /* cmp_filename, */
  1045.     /* cmp_lineno, */
  1046.     (int (*)(const void *, const void *))cmp_malloc_then_free,
  1047.     (int (*)(const void *, const void *))cmp_stacktrace,
  1048.     NULL
  1049. };
  1050. int (*cmps[])(const void *, const void *) = {
  1051.     /* cmp_filename, */
  1052.     /* cmp_lineno, */
  1053.     (int (*)(const void *, const void *))cmp_malloc_then_free,
  1054.     (int (*)(const void *, const void *))cmp_leaks,
  1055.     (int (*)(const void *, const void *))cmp_ncalls,
  1056.     (int (*)(const void *, const void *))cmp_stacktrace,
  1057.     NULL
  1058. };
  1059.  
  1060. extern void
  1061. malloc_reset()
  1062. {
  1063.     int i;
  1064.     /* can't set nhists to 0, since existing header points to them */
  1065.     for (i = 0; i < nhists; ++i) {
  1066.     hists[i].ncalls = 0;
  1067.     hists[i].nbytes = 0;
  1068.     hists[i].ncalls_freed = 0;
  1069.     hists[i].nbytes_freed = 0;
  1070.     }
  1071.     ncalls_malloc = 0;
  1072.     ncalls_free = 0;
  1073.     nbytes_malloced = 0;
  1074.     nbytes_freed = 0;
  1075. }
  1076.  
  1077. extern void
  1078. malloc_info_cleanup()
  1079. {
  1080.     stacktrace_cleanup();
  1081. }
  1082.  
  1083. /*
  1084.     verbose = 0: just totals
  1085.     verbose = 1: leaks with traces
  1086.     verbose = 2: all counts with traces
  1087. */
  1088. extern void
  1089. malloc_info(int nonleaks_too,
  1090.         int stacktrace_print_depth)
  1091. {
  1092.     int orig_nhists;
  1093.     int i;
  1094.     struct hist *ptrs[MAX_MALLOCS], *h;
  1095.     char thisfile[SYMBUFSIZ];
  1096.     char thisfunc[SYMBUFSIZ];
  1097.     char avgbuf[30];
  1098.     int thisline;
  1099.  
  1100.     init_from_env();
  1101.  
  1102.     LOCK_MALLOC(1);
  1103.  
  1104.     printf("\n");
  1105.     printf("%6s %10s %10s %10s %10s\n",
  1106.         " ",
  1107.         "Mallocs",
  1108.         "Frees",
  1109.         "Diff",
  1110.         "Max Diff");
  1111.     printf("-------------------------------------------------------------\n");
  1112.     printf("%6s %10d %10d %10d %10d\n",
  1113.         "Bytes:",
  1114.         nbytes_malloced_really,
  1115.         nbytes_freed_really,
  1116.         nbytes_malloced_really-nbytes_freed_really,
  1117.         max_diff_bytes);
  1118.     printf("%6s %10d %10d %10d\n",
  1119.         "Calls:",
  1120.         ncalls_malloc_really,
  1121.         ncalls_free_really,
  1122.         ncalls_malloc_really-ncalls_free_really);
  1123.     printf("Since last reset:\n");
  1124.     printf("%6s %10d %10d %10d\n",
  1125.         "Bytes:",
  1126.         nbytes_malloced,
  1127.         nbytes_freed,
  1128.         nbytes_malloced-nbytes_freed);
  1129.     printf("%6s %10d %10d %10d\n",
  1130.         "Calls:",
  1131.         ncalls_malloc,
  1132.         ncalls_free,
  1133.         ncalls_malloc-ncalls_free);
  1134.  
  1135.     /*
  1136.     if (!verbose) {
  1137.         UNLOCK_MALLOC(1);
  1138.         return;
  1139.     }
  1140.     */
  1141.     printf("%d out of %d traces used\n", nhists, MAX_MALLOCS);
  1142. #ifdef HASH_STATS
  1143.     _malloc_history_print_stats();
  1144. #endif
  1145.  
  1146.     printf("\n");
  1147.  
  1148.     /* printf("%15s[%4s]: %3s %6s %9s %7s %9s %7s %9s\n", */
  1149.     printf("%15s[%4s]: %3s %6s %7s %7s%6s %7s %5s %9s\n",
  1150.         "Filename",
  1151.         "Line",
  1152.         "Wha",
  1153.         "Calls",
  1154.         "Bytes",
  1155.         "Avg ",
  1156.         "FCalls",
  1157.         "FBytes",
  1158.         "Diff",
  1159.         "DiffBytes");
  1160.     printf("-------------------------------------------------------------------------------\n");
  1161.  
  1162.     orig_nhists = nhists;    /* printing and the first stacktracing call malloc */
  1163.     for (i = 0; i < orig_nhists; ++i)
  1164.         ptrs[i] = hists+i;
  1165.     if (getenv("_MALLOC_DONT_SORT_BY_NCALLS"))
  1166.         multiqsort((char *)ptrs, orig_nhists,sizeof(struct hist *),oldcmps);
  1167.     else
  1168.         multiqsort((char *)ptrs, orig_nhists, sizeof(struct hist *), cmps);
  1169.  
  1170.     for (i=0; i<orig_nhists; i++) {
  1171.  
  1172.         h = ptrs[i];
  1173.  
  1174.         if (h->ncalls == 0 &&
  1175.             (h->type==type_FREE || h->ncalls_freed==0))
  1176.             continue;
  1177.  
  1178.         if (!nonleaks_too) {
  1179.             if (h->type == type_FREE)
  1180.             continue;
  1181.             if (h->ncalls == h->ncalls_freed
  1182.               && h->nbytes == h->nbytes_freed)
  1183.             continue;
  1184.         }
  1185.  
  1186.         thisfunc[0] = 0;
  1187.         thisfile[0] = 0;
  1188.         thisline = -1;
  1189.         if (h->stacktrace_depth >= 1) {
  1190.             stacktrace_get_ffl(h->stacktrace[0],
  1191.             thisfunc, thisfile, &thisline,
  1192.             SYMBUFSIZ-2, SYMBUFSIZ-2);
  1193.         }
  1194.  
  1195.         /* XXX should keep track of whether all sizes are the same */
  1196.         if (h->ncalls == 0)
  1197.             sprintf(avgbuf, " ");
  1198.         else if (h->nbytes % h->ncalls != 0)
  1199.             sprintf(avgbuf, "%d.", h->nbytes / h->ncalls);
  1200.         else
  1201.             sprintf(avgbuf, "%d ", h->nbytes / h->ncalls);
  1202.  
  1203.         if (h->type == type_MALLOC)
  1204.  
  1205.             /* printf("%15s[%4d]: %3s %6d %9d %7d %9d %7d %9d\n", */
  1206.             printf("%15s[%4d]: %3s %6d %7d %7s%6d %7d %5d %9d\n",
  1207.                 thisfile,
  1208.                 thisline,
  1209.                 "mal",
  1210.                 h->ncalls,
  1211.                 h->nbytes,
  1212.                 avgbuf,
  1213.                 h->ncalls_freed,
  1214.                 h->nbytes_freed,
  1215.                 h->ncalls-h->ncalls_freed,
  1216.                 h->nbytes-h->nbytes_freed);
  1217.         else
  1218.             printf("%15s[%4d]: %3s %6d %7d %7s\n",
  1219.                 thisfile,
  1220.                 thisline,
  1221.                 "fre",
  1222.                 h->ncalls,
  1223.                 h->nbytes,
  1224.                 avgbuf);
  1225.         /* if (verbose >= 2) */
  1226.         {
  1227.             int j;
  1228.             for (j = 0; j < h->stacktrace_depth && 
  1229.                    (j < stacktrace_print_depth
  1230.                     || stacktrace_print_depth < 0); j++) {
  1231.                 if (!h->stacktrace[j]) {
  1232.                 printf("(lost it)\n");
  1233.                 break;
  1234.                 }
  1235.                 stacktrace_get_ffl(h->stacktrace[j],
  1236.                     thisfunc, thisfile, &thisline,
  1237.                     SYMBUFSIZ-2, SYMBUFSIZ);
  1238.  
  1239.                 /* I don't wanna see the args, so there! */
  1240.                 {
  1241.                 char *p = strchr(thisfunc, '(');
  1242.                 if (p) *p = '\0';
  1243.                 }
  1244.                 if (thisfunc[strlen(thisfunc)-1] != ')')
  1245.                 strcat(thisfunc, "()");
  1246.                 printf("%-20s %s:%d (%#x)\n",
  1247.                 thisfunc,
  1248.                 thisfile,
  1249.                 thisline,
  1250.                 h->stacktrace[j]);
  1251.             }
  1252.         }
  1253.     }
  1254.  
  1255.     printf("-------------------------------------------------------------------------------\n");
  1256.  
  1257.     UNLOCK_MALLOC(1);
  1258. }
  1259.  
  1260. /*
  1261.    Gag me-- mpc's calloc doesn't call malloc, but its free is free...
  1262. */
  1263. extern void *
  1264. calloc(size_t n, size_t siz)
  1265. {
  1266.     void *p;
  1267.     int old_fillarea;
  1268.  
  1269.     init_from_env();
  1270.  
  1271.     LOCK_MALLOC(1);
  1272.  
  1273.     old_fillarea = malloc_fillarea;
  1274.     malloc_fillarea = 0;
  1275.     p = malloc(n*siz);
  1276.     malloc_fillarea = old_fillarea;
  1277.     if (p)
  1278.     bzero(p, n*siz);
  1279.  
  1280.     UNLOCK_MALLOC(1);
  1281.     return p;
  1282. }
  1283.  
  1284. extern void
  1285. cfree(void *p)
  1286. {
  1287.     free(p);
  1288. }
  1289.  
  1290. /*
  1291. Smart:
  1292.     580 out of 600 traces used
  1293.     13 max pileup
  1294.     144 distinct pileups
  1295.     309 total pileups
  1296.     290 distinct collisions
  1297.     536 total collisions
  1298. Stupid:
  1299.     581 out of 600 traces used
  1300.     10 max pileup
  1301.     150 distinct pileups
  1302.     357 total pileups
  1303.     281 distinct collisions
  1304.     626 total collisions
  1305.  
  1306. With crowded hash table:
  1307. Smart:
  1308.     581 out of 600 traces used
  1309.     17 max pileup
  1310.     229 distinct pileups
  1311.     652 total pileups
  1312.     692 distinct collisions
  1313.     1596 total collisions
  1314. Stupid:
  1315.     580 out of 600 traces used
  1316.     60 max pileup
  1317.     227 distinct pileups
  1318.     542 total pileups
  1319.     1494 distinct collisions
  1320.     3273 total collisions
  1321. */
  1322.  
  1323. #ifdef GETWD_PATCH
  1324. extern void
  1325. force_loading_of_getwd()
  1326. {
  1327.     char buf[MAXPATHLEN+1];
  1328.     getwd(buf);
  1329. }
  1330. #endif /* GETWD_PATCH */
  1331.  
  1332. extern void
  1333. bzero(void *b, int length)    /* XXX why is this not getting found by rld? */
  1334. {
  1335.     int i;
  1336.     init_from_env();
  1337.     for (i = 0; i < length; ++i)
  1338.     ((char *)b)[i] = 0;
  1339. }
  1340.